import serial
import struct
import time
import datetime
from enum import Enum

# 串口配置
SERIAL_PORT = '/dev/ttyUSB0'  # 根据实际串口修改
BAUD_RATE = 115200

class DeviceType(Enum):
    """设备类型枚举"""
    TEMP_HUMID_SENSOR = 0x55A1    # 温湿度传感器
    MOTOR_CONTROLLER = 0x55A2     # 电机控制器
    LED_CONTROLLER = 0x55A3       # LED控制器
    BUTTON_STATUS = 0x55A4        # 按键状态
    SYSTEM_STATUS = 0x55A5        # 系统状态

def calculate_crc(data):
    """CRC16 MODBUS 校验算法"""
    crc = 0xFFFF
    for byte in data:
        crc ^= byte
        for _ in range(8):
            if crc & 0x01:
                crc = (crc >> 1) ^ 0xA001
            else:
                crc = crc >> 1
    return crc

def parse_field_data(field_type, field_data):
    """解析字段数据"""
    if field_type == 0x01:  # 有符号整型
        if len(field_data) == 4:
            return struct.unpack('>i', field_data)[0]
        return None
    elif field_type == 0x02:  # 浮点型
        if len(field_data) == 4:
            return struct.unpack('>f', field_data)[0]
        return None
    elif field_type == 0x03:  # 无符号整型
        if len(field_data) == 4:
            return struct.unpack('>I', field_data)[0]
        return None
    elif field_type == 0x04:  # 字符串
        return field_data.rstrip(b'\x00').decode('utf-8', errors='replace')
    elif field_type == 0x05:  # 布尔型
        if len(field_data) == 1:
            return bool(field_data[0])
        return None
    return field_data.hex()

def parse_temp_humid_data(fields):
    """解析温湿度传感器数据"""
    if len(fields) >= 3:
        temperature = fields[0]  # 温度(浮点型)
        humidity = fields[1]     # 湿度(浮点型)
        status = fields[2]       # 状态(布尔型)
        
        return {
            'temperature': f"{temperature:.1f}°C" if temperature is not None else "N/A",
            'humidity': f"{humidity:.1f}%" if humidity is not None else "N/A",
            'status': "正常" if status else "异常" if status is not None else "N/A"
        }
    return {}

def parse_motor_data(fields):
    """解析电机控制器数据"""
    if len(fields) >= 4:
        speed = fields[0]      # 速度(有符号整型)
        position = fields[1]   # 位置(无符号整型)
        direction = fields[2]  # 方向(布尔型)
        enabled = fields[3]    # 使能(布尔型)
        
        direction_str = "正转" if direction == 1 else "反转" if direction == -1 else "停止"
        
        return {
            'speed': f"{speed} RPM" if speed is not None else "N/A",
            'position': f"{position}" if position is not None else "N/A",
            'direction': direction_str if direction is not None else "N/A",
            'enabled': "启用" if enabled else "禁用" if enabled is not None else "N/A"
        }
    return {}

def parse_led_data(fields):
    """解析LED控制器数据"""
    if len(fields) >= 4:
        red = fields[0]    # 红色亮度
        green = fields[1]  # 绿色亮度
        blue = fields[2]   # 蓝色亮度
        mode = fields[3]   # 模式
        
        mode_str = {0: "关闭", 1: "常亮", 2: "闪烁"}.get(mode, "未知")
        
        return {
            'red': f"{red}" if red is not None else "N/A",
            'green': f"{green}" if green is not None else "N/A", 
            'blue': f"{blue}" if blue is not None else "N/A",
            'color': f"RGB({red},{green},{blue})" if all(x is not None for x in [red,green,blue]) else "N/A",
            'mode': mode_str
        }
    return {}

def parse_button_data(fields):
    """解析按键状态数据"""
    if len(fields) >= 3:
        button1 = fields[0]  # 按键1
        button2 = fields[1]  # 按键2
        button3 = fields[2]  # 按键3
        
        return {
            'button1': "按下" if button1 else "松开" if button1 is not None else "N/A",
            'button2': "按下" if button2 else "松开" if button2 is not None else "N/A",
            'button3': "按下" if button3 else "松开" if button3 is not None else "N/A"
        }
    return {}

def parse_system_data(fields):
    """解析系统状态数据"""
    if len(fields) >= 4:
        uptime = fields[0]     # 运行时间(无符号整型)
        cpu_temp = fields[1]   # CPU温度(有符号整型)
        free_memory = fields[2] # 剩余内存(无符号整型)
        system_ok = fields[3]  # 系统状态(布尔型)
        
        # 格式化运行时间
        uptime_str = "N/A"
        if uptime is not None:
            hours = uptime // 3600
            minutes = (uptime % 3600) // 60
            seconds = uptime % 60
            uptime_str = f"{hours:02d}:{minutes:02d}:{seconds:02d}"
        
        return {
            'uptime': uptime_str,
            'cpu_temp': f"{cpu_temp}°C" if cpu_temp is not None else "N/A",
            'free_memory': f"{free_memory // 1024} KB" if free_memory is not None else "N/A",
            'system_status': "正常" if system_ok else "异常" if system_ok is not None else "N/A"
        }
    return {}

def get_device_name(device_type):
    """获取设备名称"""
    device_names = {
        DeviceType.TEMP_HUMID_SENSOR: "温湿度传感器",
        DeviceType.MOTOR_CONTROLLER: "电机控制器", 
        DeviceType.LED_CONTROLLER: "LED控制器",
        DeviceType.BUTTON_STATUS: "按键状态",
        DeviceType.SYSTEM_STATUS: "系统状态"
    }
    if device_type in device_names:
        return device_names[device_type]
    else:
        # device_type是枚举对象，需要获取其值
        device_value = device_type.value if hasattr(device_type, 'value') else device_type
        return f"未知设备(0x{device_value:04X})"

def parse_device_packet(packet):
    """解析设备数据包"""
    if len(packet) < 7:  # 最小包长度检查
        return None
    
    idx = 0
    
    # 解析数据头
    header = struct.unpack('>H', packet[idx:idx + 2])[0]
    idx += 2
    
    # 识别设备类型
    device_type = None
    for dt in DeviceType:
        if dt.value == header:
            device_type = dt
            break
    
    if device_type is None:
        return {
            'error': f"未知设备头部: 0x{header:04X}",
            'raw_data': packet.hex()
        }
    
    # 解析总长度
    total_length = struct.unpack('<H', packet[idx:idx + 2])[0]
    idx += 2
    
    if total_length != len(packet):
        return {
            'error': f"数据包长度不匹配: 声明{total_length}, 实际{len(packet)}",
            'device_type': device_type
        }
    
    # 解析字段数
    field_count = packet[idx]
    idx += 1
    
    # 解析字段数据
    fields = []
    for i in range(field_count):
        if idx + 2 > len(packet) - 2:  # 确保有足够空间读取字段头和CRC
            break
            
        field_type = packet[idx]
        field_length = packet[idx + 1]
        idx += 2
        
        if idx + field_length > len(packet) - 2:  # 确保有足够空间读取字段数据
            break
            
        field_data = packet[idx:idx + field_length]
        idx += field_length
        
        parsed_data = parse_field_data(field_type, field_data)
        fields.append(parsed_data)
    
    # 验证CRC
    if idx + 2 <= len(packet):
        received_crc = struct.unpack('<H', packet[idx:idx + 2])[0]
        calculated_crc = calculate_crc(packet[:-2])
        crc_valid = (received_crc == calculated_crc)
    else:
        crc_valid = False
    
    # 根据设备类型解析具体数据
    parsed_data = {}
    if device_type == DeviceType.TEMP_HUMID_SENSOR:
        parsed_data = parse_temp_humid_data(fields)
    elif device_type == DeviceType.MOTOR_CONTROLLER:
        parsed_data = parse_motor_data(fields)
    elif device_type == DeviceType.LED_CONTROLLER:
        parsed_data = parse_led_data(fields)
    elif device_type == DeviceType.BUTTON_STATUS:
        parsed_data = parse_button_data(fields)
    elif device_type == DeviceType.SYSTEM_STATUS:
        parsed_data = parse_system_data(fields)
    
    return {
        'device_type': device_type,
        'device_name': get_device_name(device_type),
        'header': f"0x{header:04X}",
        'field_count': field_count,
        'crc_valid': crc_valid,
        'data': parsed_data,
        'raw_fields': fields
    }

def format_device_output(result, timestamp):
    """格式化设备数据输出"""
    if 'error' in result:
        return f"[{timestamp}] ❌ {result['error']}"
    
    device_name = result['device_name']
    header = result['header']
    crc_status = "✅" if result['crc_valid'] else "❌"
    
    output = f"[{timestamp}] {crc_status} 【{device_name}】({header})\n"
    
    data = result['data']
    if data:
        for key, value in data.items():
            output += f"    {key}: {value}\n"
    else:
        output += f"    原始数据: {result['raw_fields']}\n"
    
    return output.rstrip()

def receive_device_data():
    """接收并解析多设备数据"""
    print("=" * 60)
    print("STM32 多设备数据接收程序")
    print("=" * 60)
    print(f"串口: {SERIAL_PORT}")
    print(f"波特率: {BAUD_RATE}")
    print("按 Ctrl+C 退出程序")
    print("-" * 60)
    
    try:
        ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
        print(f"串口 {ser.name} 已打开")
        print("等待设备数据...\n")
        
        receive_state = 0  # 0=等待头部, 1=接收数据
        buffer = bytearray()
        expected_length = 0
        
        while True:
            if ser.in_waiting > 0:
                new_data = ser.read(ser.in_waiting)
                buffer.extend(new_data)
                
                while len(buffer) >= 2:
                    if receive_state == 0:  # 等待头部
                        # 检查是否是有效的设备头部
                        header = struct.unpack('>H', buffer[:2])[0]
                        
                        valid_header = False
                        for device_type in DeviceType:
                            if device_type.value == header:
                                valid_header = True
                                break
                        
                        if valid_header and len(buffer) >= 4:
                            # 读取总长度
                            expected_length = struct.unpack('<H', buffer[2:4])[0]
                            if 7 <= expected_length <= 256:  # 合理的长度范围
                                receive_state = 1
                            else:
                                buffer = buffer[1:]  # 移除第一个字节，继续搜索
                        else:
                            buffer = buffer[1:]  # 移除第一个字节，继续搜索
                    
                    elif receive_state == 1:  # 接收数据
                        if len(buffer) >= expected_length:
                            # 提取完整数据包
                            packet = buffer[:expected_length]
                            buffer = buffer[expected_length:]
                            
                            # 解析数据包
                            timestamp = datetime.datetime.now().strftime("%H:%M:%S.%f")[:-3]
                            result = parse_device_packet(packet)
                            
                            if result:
                                print(format_device_output(result, timestamp))
                                print()  # 空行分隔
                            
                            # 重置状态
                            receive_state = 0
                            expected_length = 0
                        else:
                            break  # 等待更多数据
                
                # 防止缓冲区过大
                if len(buffer) > 512:
                    buffer = buffer[-256:]
                    receive_state = 0
            
            time.sleep(0.01)
            
    except serial.SerialException as e:
        print(f"串口错误: {e}")
        print("请检查串口连接和配置")
    except KeyboardInterrupt:
        print("\n程序被用户中断")
    except Exception as e:
        print(f"程序异常: {e}")
    finally:
        try:
            ser.close()
            print("串口已关闭")
        except:
            pass

if __name__ == "__main__":
    receive_device_data() 